/* 
 * File:   ResourceManager.cpp
 * 
 * Copyright (C) 2008, 2009
 *		Sergio Padrino Recio (PadrinatoR)
 *		J. Daniel Expósito Polo (HellSpawn666)
 *		kasikiare
 *
 * Created on 8 de septiembre de 2008, 20:34
 *
 * This file is part of BombProject.
 * 
 * BombProject is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
   
 * BombProject is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with BombProject.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "ResourceManager.h"

#include <SDL/SDL_image.h>
#include <stdio.h>

/**
 * Clears the content of both maps.
 */
template <class T> void ResourceMap<T>::clear(){
	resourcesMap.clear();
	stringsMap.clear();
}

/**
 * Returns a resource entry from a given file name.
 * @param filename File name of the resource.
 * @return Resource entry.
 */
template <class T> struct ResourceEntry<T>* ResourceMap<T>::get(string filename){
	return resourcesMap[filename];
}

/**
 * Returns a resource entry from a given pointer to resource (SDL_Surface, for example).
 * @param resource Pointer to a resource.
 * @return Resource entry.
 */
template <class T> struct ResourceEntry<T>* ResourceMap<T>::get(T* resource){
	if(stringsMap.find(resource) != stringsMap.end()){
		string filename = stringsMap[resource];
	
		return resourcesMap[filename];
	}else{
		return NULL;
	}
}

/**
 * Erases a resource from a given pointer to resource (SDL_Surface, for example).
 * @param resource Pointer to a resource.
 */
template <class T> void ResourceMap<T>::erase(T* resource){
	string filename = stringsMap[resource];
	
	stringsMap.erase(resource);
	resourcesMap.erase(filename);
}

/**
 * Adds a resource to the resource map.
 * @param filename File name of the resource.
 * @param resource A resource entry which contains data about the resource to be added.
 */
template <class T> void ResourceMap<T>::add(string filename, struct ResourceEntry<T>* resource){
	
	resourcesMap[filename] = resource;
	stringsMap[resource->resource] = filename;
}

/**
 * Instance of the resource manager.
 */
ResourceManager* ResourceManager::mInstance = NULL;

/**
 * Constructor.
 */
ResourceManager::ResourceManager(){
	imagesList.clear();
}

/**
 * Destructor.
 */
ResourceManager::~ResourceManager(){
}

/**
 * Returns the instance of the resource manager, following the Singleton pattern.
 * @return Global instance of the resource manager.
 */
ResourceManager* ResourceManager::getInstance(){
	if(!mInstance)
		mInstance = new ResourceManager();
		
	return mInstance;
}

/**
 * Deletes the global instance of the resource manager.
 */
void ResourceManager::deleteInstance(){
	if(!mInstance)
		delete mInstance;
}

/**
 * Loads an image and stores it in the corresponding resource map.
 * @param filename File name.
 * @return Loaded image's surface.
 */
SDL_Surface* ResourceManager::loadImage(string filename){
	ResourceEntry<SDL_Surface>* entry = imagesList.get(filename);
	
	//If the image wasn't loaded
	if(entry == NULL) {
		SDL_Surface* aux = IMG_Load(filename.c_str());
		
		if(aux == NULL){
			fprintf(stderr, "ResourceManager::loadImage - Image %s couldn't be loaded\n", filename.c_str());
			return NULL;
		}
	
		entry = new ResourceEntry<SDL_Surface>();
		entry->numReferences = 0;
		entry->resource = SDL_DisplayFormat(aux);
	
		SDL_FreeSurface(aux);
		
		imagesList.add(filename, entry);
	}
	
	//Increase the number of references to that image
	entry->numReferences++;
	
	return entry->resource;
}

/**
 * Unloads an image and deletes it from the map if it's not referenced anymore.
 * @param image Surface to be unloaded.
 */
void ResourceManager::unloadImage(SDL_Surface* image){
	ResourceEntry<SDL_Surface>* entry = imagesList.get(image);
	
	if(!entry){
		fprintf(stderr, "ResourceManager::unloadImage - SDL_Surface wasn't loaded\n");
		return;
	}else if(entry->numReferences > 1){
		entry->numReferences--;
	}else{
		imagesList.erase(entry->resource);

		SDL_FreeSurface(entry->resource);
		
		delete entry;
	}
}
